"""
健康数据处理器

处理IoT设备的健康数据，包括心率、血压、体温等生理指标的监测和异常预警
"""

from typing import Dict, Any, Optional, List

from .base_handler import BaseHandler
from dao.es_dao.card_dao import update_card_wearing, update_health
from dao.es_dao.p_health_log_dao import save_all_health
from dao.mongo_dao.wechat_login_dao import find_wechat_login
from model.es.card import ElectronicCardModel
from model.wristband_models import HealthData
from service.battery import get_intensity_redis
from utils.date_utils import timestamp_to_str
from utils.health_utils import (
    blood_pressure_valid, generate_heart_rate_wechat_template, 
    temperature_valid, build_body_temperature_keyword
)
from utils.wechat_message_util import (
    WechatTokenManager, build_wechat_message_data, send_template_message
)


class HealthHandler(BaseHandler):
    """健康数据处理器"""
    
    # 微信模板ID常量
    BLOOD_PRESSURE_TEMPLATE_ID = 'W3m9Rpek7r97XkK3d2ztp24JcgqmdKqdLORplbW3Cj8'
    HEART_RATE_TEMPLATE_ID = 'BbC-bhVMxpNM3j790moW-LN_go84mnpKAURAjkQfnwQ'
    TEMPERATURE_TEMPLATE_ID = 'nGFpGtRdS9ARfIsCJ8ZckZfLkDlJFIvOb_p_zcwPtbY'
    
    def __init__(self):
        super().__init__()
        self.wechat_token_manager = WechatTokenManager()
    
    async def handle(self, device_id: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """
        处理健康数据
        
        Args:
            device_id: 设备ID
            data: 健康数据字典
            
        Returns:
            处理结果
        """
        try:
            # 将字典数据转换为HealthData模型
            health = HealthData(**data)
            await self._process_health_data(health)
            return {"status": "success", "device_id": device_id}
            
        except Exception as e:
            self.log_error(device_id, "健康", e)
            return None
    
    async def _process_health_data(self, health: HealthData) -> None:
        """
        处理健康数据的核心逻辑
        
        业务流程：
        1. 获取设备卡片信息
        2. 更新设备佩戴状态（基于心率数据）
        3. 更新设备在线状态
        4. 保存健康数据到数据库
        5. 进行健康异常检测和预警
        
        Args:
            health: 健康数据模型
        """
        # 步骤1: 获取设备卡片信息
        card = await self.get_device_card(health.device_id)
        if not card:
            self.logger.warning(f"未找到设备卡片信息: {health.device_id}")
            return
        
        # 步骤2: 更新佩戴状态（有心率数据说明正在佩戴）
        await self._update_wearing_status(health, card.es_id)
        
        # 步骤3: 更新在线状态
        await self._update_online_status(health.device_id)
        
        # 步骤4: 更新设备健康数据
        await self._update_device_health(health)
        
        # 步骤5: 保存健康数据到数据库
        await self._save_health_data(health, card)
        
        # 步骤6: 进行健康异常检测和预警
        await self._check_health_alerts(health, card)
    
    async def _update_wearing_status(self, health: HealthData, card_es_id: str) -> None:
        """
        更新设备佩戴状态
        
        Args:
            health: 健康数据
            card_es_id: 卡片ES ID
        """
        try:
            # 有心率数据且大于0表示正在佩戴
            is_wearing = health.heart_rate is not None and health.heart_rate > 0
            if is_wearing:
                await update_card_wearing(True, card_es_id)
                
        except Exception as e:
            self.logger.error(f"更新佩戴状态失败: {health.device_id}, 错误: {e}")
    
    async def _update_online_status(self, device_id: str) -> None:
        """
        更新设备在线状态
        
        Args:
            device_id: 设备ID
        """
        try:
            await self.redis_hset_async(f'state_{device_id}', 'online', 1)
        except Exception as e:
            self.logger.error(f"更新在线状态失败: {device_id}, 错误: {e}")
    
    async def _update_device_health(self, health: HealthData) -> None:
        """
        更新设备健康数据
        
        Args:
            health: 健康数据
        """
        try:
            await update_health(health)
        except Exception as e:
            self.logger.error(f"更新健康数据失败: {health.device_id}, 错误: {e}")
    
    async def _save_health_data(self, health: HealthData, card: ElectronicCardModel) -> None:
        """
        保存健康数据到数据库
        
        Args:
            health: 健康数据
            card: 设备卡片信息
        """
        try:
            # 获取活动强度数据
            intensity_dict = await get_intensity_redis(health.device_id)
            
            # 保存到ES数据库
            await save_all_health(
                health, 
                card.dataAuthority.model_dump(), 
                intensity_dict
            )
            
        except Exception as e:
            self.logger.error(f"保存健康数据失败: {health.device_id}, 错误: {e}")
    
    async def _check_health_alerts(self, health: HealthData, card: ElectronicCardModel) -> None:
        """
        检查健康异常并发送预警
        
        Args:
            health: 健康数据
            card: 设备卡片信息
        """
        try:
            # 获取考勤状态和活动强度
            clock_state = await self.redis_hget_async('clock_state', health.device_id)
            intensity_dict = await get_intensity_redis(health.device_id)
            intensity = intensity_dict.get('intensity', 0)
            
            # 只有在工作状态（clock_state=1）且活动强度较低时才进行健康预警
            if clock_state == b'1' and intensity < 2:
                await self._process_health_warnings(health, card, intensity)
                
        except Exception as e:
            self.logger.error(f"健康预警检查失败: {health.device_id}, 错误: {e}")
    
    async def _process_health_warnings(self, health: HealthData, card: ElectronicCardModel, 
                                     intensity: int) -> None:
        """
        处理健康预警逻辑
        
        Args:
            health: 健康数据
            card: 设备卡片信息
            intensity: 活动强度
        """
        # 获取微信通知的接收者列表
        openid_list = None
        wechat_token = None
        
        try:
            # 检查血压异常
            await self._check_blood_pressure_alert(
                health, card, openid_list, wechat_token
            )
            
            # 检查心率异常
            await self._check_heart_rate_alert(
                health, card, intensity, openid_list, wechat_token
            )
            
            # 检查体温异常
            await self._check_temperature_alert(
                health, card, openid_list, wechat_token
            )
            
        except Exception as e:
            self.logger.error(f"处理健康预警失败: {health.device_id}, 错误: {e}")
    
    async def _check_blood_pressure_alert(self, health: HealthData, card: ElectronicCardModel,
                                        openid_list: Optional[List], wechat_token: Optional[str]) -> tuple:
        """
        检查血压异常预警
        
        Args:
            health: 健康数据
            card: 设备卡片信息
            openid_list: 微信接收者列表
            wechat_token: 微信访问令牌
            
        Returns:
            (更新后的openid_list, 更新后的wechat_token)
        """
        try:
            # 验证血压数据
            blood_pressure_data = blood_pressure_valid(
                health.blood_pressure_high, 
                health.blood_pressure_low
            )
            
            if blood_pressure_data and blood_pressure_data.get('warning_level', 0) > 2:
                self.logger.info(f"检测到血压异常: {health.device_id}")
                
                # 获取微信通知接收者
                if openid_list is None:
                    openid_list = find_wechat_login(str(card.depart))
                
                # 获取微信访问令牌
                if wechat_token is None:
                    wechat_token = await self.wechat_token_manager.get_token()
                
                # 构建血压预警消息
                keyword_data = {
                    'thing4': {'value': card.name, "color": "#173177"},
                    'character_string3': {'value': blood_pressure_data['value']},
                    'const5': {'value': blood_pressure_data['blood_pressure_level']},
                    'time1': {'value': timestamp_to_str(float(health.timestamp))},
                    'const10': {'value': blood_pressure_data['advice']}
                }
                
                # 发送微信模板消息
                await self._send_wechat_alerts(
                    keyword_data, openid_list, wechat_token, 
                    self.BLOOD_PRESSURE_TEMPLATE_ID
                )
                
        except Exception as e:
            self.logger.error(f"血压预警检查失败: {health.device_id}, 错误: {e}")
        
        return openid_list, wechat_token
    
    async def _check_heart_rate_alert(self, health: HealthData, card: ElectronicCardModel,
                                    intensity: int, openid_list: Optional[List], 
                                    wechat_token: Optional[str]) -> tuple:
        """
        检查心率异常预警
        
        Args:
            health: 健康数据
            card: 设备卡片信息
            intensity: 活动强度
            openid_list: 微信接收者列表
            wechat_token: 微信访问令牌
            
        Returns:
            (更新后的openid_list, 更新后的wechat_token)
        """
        try:
            # 生成心率预警模板数据
            heart_rate_data = await generate_heart_rate_wechat_template(
                health.heart_rate, health.device_id, card.name, 
                health.timestamp, intensity
            )
            
            if heart_rate_data:
                self.logger.info(f"检测到心率异常: {health.device_id}")
                
                # 获取微信通知接收者
                if openid_list is None:
                    openid_list = find_wechat_login(str(card.depart))
                
                # 获取微信访问令牌
                if wechat_token is None:
                    wechat_token = await self.wechat_token_manager.get_token()
                
                # 发送微信模板消息
                await self._send_wechat_alerts(
                    heart_rate_data, openid_list, wechat_token, 
                    self.HEART_RATE_TEMPLATE_ID
                )
                
        except Exception as e:
            self.logger.error(f"心率预警检查失败: {health.device_id}, 错误: {e}")
        
        return openid_list, wechat_token
    
    async def _check_temperature_alert(self, health: HealthData, card: ElectronicCardModel,
                                     openid_list: Optional[List], wechat_token: Optional[str]) -> tuple:
        """
        检查体温异常预警
        
        Args:
            health: 健康数据
            card: 设备卡片信息
            openid_list: 微信接收者列表
            wechat_token: 微信访问令牌
            
        Returns:
            (更新后的openid_list, 更新后的wechat_token)
        """
        if health.body_temperature <= 0:
            return openid_list, wechat_token
        
        try:
            # 验证体温数据
            temperature_alert = temperature_valid(float(health.body_temperature))
            
            if temperature_alert:
                self.logger.info(f"检测到体温异常: {health.device_id}")
                
                # 获取微信通知接收者
                if openid_list is None:
                    openid_list = find_wechat_login(str(card.depart))
                
                # 获取微信访问令牌
                if wechat_token is None:
                    wechat_token = await self.wechat_token_manager.get_token()
                
                # 构建体温预警消息
                keyword_data = build_body_temperature_keyword(
                    temperature_alert, health.body_temperature,
                    card.depart_name, card.name, float(health.timestamp)
                )
                
                # 发送微信模板消息
                await self._send_wechat_alerts(
                    keyword_data, openid_list, wechat_token, 
                    self.TEMPERATURE_TEMPLATE_ID
                )
                
        except Exception as e:
            self.logger.error(f"体温预警检查失败: {health.device_id}, 错误: {e}")
        
        return openid_list, wechat_token
    
    async def _send_wechat_alerts(self, keyword_data: Dict, openid_list: List,
                                wechat_token: str, template_id: str) -> None:
        """
        发送微信预警消息
        
        Args:
            keyword_data: 模板关键词数据
            openid_list: 微信接收者列表
            wechat_token: 微信访问令牌
            template_id: 微信模板ID
        """
        try:
            # 构建微信消息数据
            message_data_list = build_wechat_message_data(
                keyword_data=keyword_data,
                openid_list=openid_list,
                template_id=template_id
            )
            
            # 批量发送消息
            for message_data in message_data_list:
                await send_template_message(message_data, wechat_token)
                
        except Exception as e:
            self.logger.error(f"发送微信预警消息失败: 错误: {e}")